package com.haixiaoke.saas.messageCenter.service.impl;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.haixiaoke.saas.common.constant.Constants;
import com.haixiaoke.saas.common.constant.MessageConstants;
import com.haixiaoke.saas.common.core.domain.AjaxResult;
import com.haixiaoke.saas.common.core.redis.RedisCache;
import com.haixiaoke.saas.common.exception.ServiceException;
import com.haixiaoke.saas.common.utils.DateUtils;
import com.haixiaoke.saas.message.Message;
import com.haixiaoke.saas.message.MessageHub;
import com.haixiaoke.saas.messageCenter.domain.MessageChannel;
import com.haixiaoke.saas.messageCenter.domain.OrdinaryMessage;
import com.haixiaoke.saas.messageCenter.domain.OrdinaryMessageUser;
import com.haixiaoke.saas.messageCenter.domain.PushRecord;
import com.haixiaoke.saas.messageCenter.mapper.OrdinaryMessageMapper;
import com.haixiaoke.saas.messageCenter.service.*;
import com.haixiaoke.saas.system.framework.manager.AsyncManager;
import com.haixiaoke.saas.system.framework.manager.factory.AsyncFactory;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * 普通消息推送Service业务层处理
 *
 * @author panda
 * @date 2024-11-08
 */
@Slf4j
@Service
public class OrdinaryMessageServiceImpl implements IOrdinaryMessageService {
    @Autowired
    private OrdinaryMessageMapper ordinaryMessageMapper;
    @Autowired
    private IOrdinaryMessageUserService ordinaryMessageUserService;
    @Autowired
    private IPushConditionService pushConditionService;
    @Autowired
    private IMessageChannelService messageChannelService;
    @Autowired
    private RedisCache redisCache;
    @Autowired
    private IPushRecordService pushRecordService;

    /**
     * 查询普通消息推送
     *
     * @param ordinaryMessageId 普通消息推送主键
     * @return 普通消息推送
     */
    @Override
    public OrdinaryMessage selectOrdinaryMessageByOrdinaryMessageId(Long ordinaryMessageId) {
        OrdinaryMessage ordinaryMessage = ordinaryMessageMapper.selectOrdinaryMessageByOrdinaryMessageId(ordinaryMessageId);
        if (ObjectUtil.isNotEmpty(ordinaryMessage)) {
            List<OrdinaryMessageUser> messageUserList = ordinaryMessageUserService.selectOrdinaryMessageUserByOrdinaryMessageId(ordinaryMessageId);
            ordinaryMessage.setOrdinaryMessageUserList(messageUserList);
        }
        return ordinaryMessage;
    }

    /**
     * 查询普通消息推送列表
     *
     * @param ordinaryMessage 普通消息推送
     * @return 普通消息推送
     */
    @Override
    public List<OrdinaryMessage> selectOrdinaryMessageList(OrdinaryMessage ordinaryMessage) {
        return ordinaryMessageMapper.selectOrdinaryMessageList(ordinaryMessage);
    }

    /**
     * 新增普通消息推送
     *
     * @param ordinaryMessage 普通消息推送
     * @return 结果
     */
    @Override
    @Transactional
    public AjaxResult insertOrdinaryMessage(OrdinaryMessage ordinaryMessage) {
        AjaxResult ajaxResult = checkOrdinaryMessageParam(ordinaryMessage);
        if (ajaxResult != null) {
            return ajaxResult;
        }
        ordinaryMessage.setCreateTime(DateUtils.getNowDate());
        // 生成模版编码
        String code = "MT_" + RandomUtil.randomNumbers(7);
        ordinaryMessage.setTemplateCode(code);

        int result = ordinaryMessageMapper.insertOrdinaryMessage(ordinaryMessage);
        if (result <= 0) {
            return AjaxResult.error("新增普通消息失败");
        }

        //新增普通消息推送的用户
        if (CollectionUtil.isNotEmpty(ordinaryMessage.getOrdinaryMessageUserList()) &&
                !StrUtil.equals(MessageConstants.TRIGGERING_BEHAVIOR_CONDITION_PUSH, ordinaryMessage.getTriggeringBehavior())) {
            //设置消息ID
            ordinaryMessage.getOrdinaryMessageUserList().forEach(x -> x.setOrdinaryMessageId(ordinaryMessage.getOrdinaryMessageId()));
            //批量插入普通消息推送与用户关联数据
            ordinaryMessageUserService.insertBatchOrdinaryMessageUser(ordinaryMessage.getOrdinaryMessageUserList());
        }

        //立即发送
        if (StrUtil.equals(MessageConstants.TRIGGERING_BEHAVIOR_PUSH_NOW, ordinaryMessage.getTriggeringBehavior()) &&
                StrUtil.equals(MessageConstants.ORDINARY_MESSAGE_STATE_ENABLE, ordinaryMessage.getOrdinaryMessageState())) {
            this.sendMessage(ordinaryMessage);
        }

        return AjaxResult.success();
    }

    @Override
    public void sendMessage(OrdinaryMessage ordinaryMessage) {
        if (CollectionUtil.isEmpty(ordinaryMessage.getOrdinaryMessageUserList())) {
            throw new ServiceException("推送目标不能为空");
        }

        String redisKey = MessageConstants.ORDINARY_MESSAGE_CACHE_PREFIX + ordinaryMessage.getOrdinaryMessageId();
        if (redisCache.hasKey(redisKey)) {
            throw new ServiceException("消息正在推送,请勿重复推送");
        }

        //设置缓存key,防止重复推送消息
        redisCache.setCacheObject(redisKey, ordinaryMessage.getOrdinaryMessageId(), 1, TimeUnit.HOURS);
        //异步发送消息
        AsyncManager.me().execute(AsyncFactory.sendOrdinaryMessage(ordinaryMessage));
    }

    @Override
    public void sendOrdinaryMessage(OrdinaryMessage ordinaryMessage) {
        try {
            List<OrdinaryMessageUser> messageUserList = ordinaryMessage.getOrdinaryMessageUserList();
            ArrayList<PushRecord> pushRecordList = new ArrayList<>();
            if (StrUtil.equals(MessageConstants.ORDINARY_MESSAGE_TYPE_OUT, ordinaryMessage.getOrdinaryMessageType())) {
                //应用外
                //校验消息渠道是否存在
                MessageChannel messageChannel = messageChannelService.selectMessageChannelByTenantId(ordinaryMessage.getTenantId());
                if (ObjectUtil.isEmpty(messageChannel)) {
                    throw new ServiceException("消息渠道不存在,请先配置消息渠道");
                }
                //封装微信、钉钉消息
                Message message = new Message();
                message.setMessageContent(ordinaryMessage.getMessageContent());
                String[] pushChannels = ordinaryMessage.getPushChannel().split(",");
                for (String pushChannel : pushChannels) {
                    //校验消息渠道是否开启
                    //企业微信参数
                    if (StrUtil.equals(MessageConstants.PUSH_CHANNEL_ENTERPRISE_WECHAT, pushChannel)) {
                        if (StrUtil.equals(Constants.OPEN, messageChannel.getWechatState())) {
                            message.setWechatState(Constants.OPEN);
                            message.setWechatCorpid(messageChannel.getWechatCorpid());
                            message.setWechatAgentId(messageChannel.getWechatAgentId());
                            message.setWechatSecret(messageChannel.getWechatSecret());
                        } else if (StrUtil.equals(Constants.SHUT, messageChannel.getWechatState())) {
                            throw new ServiceException("企业微信渠道未开启,请先开启企业微信渠道");
                        }
                    }
                    //钉钉
                    if (StrUtil.equals(MessageConstants.PUSH_CHANNEL_DING_TALK, pushChannel)) {
                        if (StrUtil.equals(Constants.OPEN, messageChannel.getDingState())) {
                            message.setDingState(Constants.OPEN);
                            message.setDingAgentId(messageChannel.getDingAgentId());
                            message.setDingAppKey(messageChannel.getDingAppKey());
                            message.setDingAppSecret(messageChannel.getDingAppSecret());
                        } else if (StrUtil.equals(Constants.SHUT, messageChannel.getWechatState())) {
                            throw new ServiceException("钉钉渠道未开启,请先开启钉钉渠道");
                        }
                    }
                }
                for (OrdinaryMessageUser messageUser : messageUserList) {
                    message.setReceiverPhone(messageUser.getUserPhone());
                    //调用第三方发送消息
                    Map<String, String> resultMap = MessageHub.messageEventManage.sendMessage(message);
                    //封装推送记录
                    //企业微信推送记录
                    if (StrUtil.equals(Constants.OPEN, message.getWechatState())) {
                        String pushResult = resultMap.get(MessageConstants.PUSH_CHANNEL_ENTERPRISE_WECHAT);
                        addPushRecord(ordinaryMessage, pushRecordList, messageUser, pushResult, MessageConstants.ORDINARY_MESSAGE_TYPE_OUT, MessageConstants.PUSH_CHANNEL_ENTERPRISE_WECHAT);
                    }

                    //钉钉推送记录
                    if (StrUtil.equals(Constants.OPEN, message.getDingState())) {
                        String pushResult = resultMap.get(MessageConstants.PUSH_CHANNEL_DING_TALK);
                        addPushRecord(ordinaryMessage, pushRecordList, messageUser, pushResult, MessageConstants.ORDINARY_MESSAGE_TYPE_OUT, MessageConstants.PUSH_CHANNEL_DING_TALK);
                    }
                }
            } else if (StrUtil.equals(MessageConstants.ORDINARY_MESSAGE_TYPE_IN, ordinaryMessage.getOrdinaryMessageType())) {
                //应用内
                if (ordinaryMessage.getPushChannel().split(",").length > 1) {
                    throw new ServiceException("应用内推送渠道只能单选");
                }

                //封装推送记录
                if (StrUtil.equals(MessageConstants.PUSH_CHANNEL_MERCHANT_APPLET, ordinaryMessage.getPushChannel())) {
                    //商家小程序
                    for (OrdinaryMessageUser messageUser : messageUserList) {
                        addPushRecord(ordinaryMessage, pushRecordList, messageUser, null, MessageConstants.ORDINARY_MESSAGE_TYPE_IN, MessageConstants.PUSH_CHANNEL_MERCHANT_APPLET);
                    }
                } else if (StrUtil.equals(MessageConstants.PUSH_CHANNEL_RENTER_APPLET, ordinaryMessage.getPushChannel())) {
                    //租客小程序
                    for (OrdinaryMessageUser messageUser : messageUserList) {
                        addPushRecord(ordinaryMessage, pushRecordList, messageUser, null, MessageConstants.ORDINARY_MESSAGE_TYPE_IN, MessageConstants.PUSH_CHANNEL_RENTER_APPLET);
                    }
                }
            }

            //批量新增推送记录
            if (CollectionUtil.isNotEmpty(pushRecordList)) {
                pushRecordService.insertBatchPushRecordList(pushRecordList);
            }
        } catch (Exception e) {
            log.error("发送普通消息失败,原因:", e);
        } finally {
            redisCache.deleteObject(MessageConstants.ORDINARY_MESSAGE_CACHE_PREFIX + ordinaryMessage.getOrdinaryMessageId());
        }
    }

    private void addPushRecord(OrdinaryMessage ordinaryMessage, ArrayList<PushRecord> pushRecordList, OrdinaryMessageUser messageUser, String pushResult, String messageType, String pushChannel) {
        PushRecord pushRecord = new PushRecord();
        BeanUtil.copyProperties(ordinaryMessage, pushRecord);
        pushRecord.setPushChannel(pushChannel);
        pushRecord.setPushResult(pushResult);
        pushRecord.setPushTime(DateUtils.getNowDate());
        pushRecord.setUserId(messageUser.getUserId());
        pushRecord.setRecipient(StrUtil.isEmpty(messageUser.getUserName()) ? messageUser.getUserPhone() : messageUser.getUserName());
        pushRecord.setBusinessId(messageUser.getBusinessId());
        pushRecord.setMessageType(messageType);
        pushRecord.setCreateTime(DateUtils.getNowDate());
        pushRecord.setBusinessType(messageUser.getBusinessType());
        pushRecordList.add(pushRecord);
    }

    /**
     * 修改普通消息推送
     *
     * @param ordinaryMessage 普通消息推送
     * @return 结果
     */
    @Override
    public AjaxResult updateOrdinaryMessage(OrdinaryMessage ordinaryMessage) {
        AjaxResult ajaxResult = checkOrdinaryMessageParam(ordinaryMessage);
        if (ajaxResult != null) {
            return ajaxResult;
        }
        if (StrUtil.equals(MessageConstants.TRIGGERING_BEHAVIOR_PUSH_NOW, ordinaryMessage.getTriggeringBehavior()) &&
                StrUtil.equals(MessageConstants.ORDINARY_MESSAGE_STATE_ENABLE, ordinaryMessage.getOrdinaryMessageState())) {
            String redisKey = MessageConstants.ORDINARY_MESSAGE_CACHE_PREFIX + ordinaryMessage.getOrdinaryMessageId();
            if (redisCache.hasKey(redisKey)) {
                throw new ServiceException("消息正在推送,请稍后再修改");
            }
        }
        ordinaryMessage.setUpdateTime(DateUtils.getNowDate());
        int result = ordinaryMessageMapper.updateOrdinaryMessage(ordinaryMessage);
        if (result <= 0) {
            return AjaxResult.error("编辑普通消息失败");
        }
        //删除普通消息推送的用户数据
        ordinaryMessageUserService.deleteOrdinaryMessageUserByOrdinaryMessageId(ordinaryMessage.getOrdinaryMessageId());
        //新增普通消息推送的用户
        if (CollectionUtil.isNotEmpty(ordinaryMessage.getOrdinaryMessageUserList()) &&
                !StrUtil.equals(MessageConstants.TRIGGERING_BEHAVIOR_CONDITION_PUSH, ordinaryMessage.getTriggeringBehavior())) {
            //设置消息ID
            ordinaryMessage.getOrdinaryMessageUserList().forEach(x -> x.setOrdinaryMessageId(ordinaryMessage.getOrdinaryMessageId()));
            //批量插入普通消息推送与用户关联数据
            ordinaryMessageUserService.insertBatchOrdinaryMessageUser(ordinaryMessage.getOrdinaryMessageUserList());
        }

        //立即发送
        if (StrUtil.equals(MessageConstants.TRIGGERING_BEHAVIOR_PUSH_NOW, ordinaryMessage.getTriggeringBehavior()) &&
                StrUtil.equals(MessageConstants.ORDINARY_MESSAGE_STATE_ENABLE, ordinaryMessage.getOrdinaryMessageState())) {
            this.sendMessage(ordinaryMessage);
        }

        return AjaxResult.success();
    }

    /**
     * 批量删除普通消息推送
     *
     * @param ordinaryMessageIds 需要删除的普通消息推送主键
     * @return 结果
     */
    @Override
    public int deleteOrdinaryMessageByOrdinaryMessageIds(Long[] ordinaryMessageIds) {
        return ordinaryMessageMapper.deleteOrdinaryMessageByOrdinaryMessageIds(ordinaryMessageIds);
    }

    /**
     * 删除普通消息推送信息
     *
     * @param ordinaryMessageId 普通消息推送主键
     * @return 结果
     */
    @Override
    @Transactional
    public int deleteOrdinaryMessageByOrdinaryMessageId(Long ordinaryMessageId) {
        ordinaryMessageUserService.deleteOrdinaryMessageUserByOrdinaryMessageId(ordinaryMessageId);
        return ordinaryMessageMapper.deleteOrdinaryMessageByOrdinaryMessageId(ordinaryMessageId);
    }

    @Override
    public List<OrdinaryMessage> selectOrdinaryMessageByTenantId(String tenantId) {
        return ordinaryMessageMapper.selectOrdinaryMessageByTenantId(tenantId);
    }

    @Override
    public List<OrdinaryMessage> selectOrdinaryMessageByTenantIdAndPushChannel(String tenantId, String pushChannel) {
        return ordinaryMessageMapper.selectOrdinaryMessageByTenantIdAndPushChannel(tenantId, pushChannel);
    }

    @Override
    public void sendMessageTask() {
        List<OrdinaryMessage> ordinaryMessageList = ordinaryMessageMapper.selectOrdinaryMessageListByTask();
        List<OrdinaryMessageUser> ordinaryMessageUserList = new ArrayList<>();
        if (CollectionUtil.isNotEmpty(ordinaryMessageList)) {
            for (OrdinaryMessage ordinaryMessage : ordinaryMessageList) {
                //触发行为为指定条件则获取符合条件的用户
                if (StrUtil.equals(MessageConstants.TRIGGERING_BEHAVIOR_CONDITION_PUSH, ordinaryMessage.getTriggeringBehavior())) {
                    List<OrdinaryMessageUser> messageUserList = ordinaryMessageUserService.getUserByPushCondition(ordinaryMessage);
                    if (CollectionUtil.isNotEmpty(messageUserList)) {
                        ordinaryMessageUserList.addAll(messageUserList);
                    }
                    ordinaryMessage.setOrdinaryMessageUserList(messageUserList);
                }
                if (CollectionUtil.isEmpty(ordinaryMessage.getOrdinaryMessageUserList())) {
                    continue;
                }
                this.sendMessage(ordinaryMessage);
            }
        }
        if (CollectionUtil.isNotEmpty(ordinaryMessageUserList)) {
            ordinaryMessageUserService.insertBatchOrdinaryMessageUser(ordinaryMessageUserList);
        }
    }

    public AjaxResult checkOrdinaryMessageParam(OrdinaryMessage ordinaryMessage) {
        if (StrUtil.isBlank(ordinaryMessage.getTemplateName()) || ordinaryMessage.getTemplateName().length() > 20) {
            return AjaxResult.error("模板名称不能为空且不能超过20个字");
        }
        if (StrUtil.isBlank(ordinaryMessage.getMessageHeader()) || ordinaryMessage.getMessageHeader().length() > 20) {
            return AjaxResult.error("标题不能为空且不能超过20个字");
        }
        if (StrUtil.isBlank(ordinaryMessage.getMessageContent()) || ordinaryMessage.getMessageContent().length() > 200) {
            return AjaxResult.error("消息内容不能为空且不能超过200个字");
        }
        if (StrUtil.isBlank(ordinaryMessage.getPushChannel())) {
            return AjaxResult.error("推送渠道不能为空");
        }
        if (!StrUtil.equals(MessageConstants.TRIGGERING_BEHAVIOR_CONDITION_PUSH, ordinaryMessage.getTriggeringBehavior())) {
            if (CollectionUtil.isEmpty(ordinaryMessage.getOrdinaryMessageUserList())) {
                return AjaxResult.error("目标人群不能为空");
            }
            boolean isNull = ordinaryMessage.getOrdinaryMessageUserList().stream()
                    .anyMatch(a -> a.getUserId() == null || StrUtil.isBlank(a.getUserPhone()));
            if (isNull) {
                return AjaxResult.error("目标人群数据异常");
            }
        }
        if (StrUtil.equals(MessageConstants.TRIGGERING_BEHAVIOR_CONDITION_PUSH, ordinaryMessage.getTriggeringBehavior()) &&
                StrUtil.isBlank(ordinaryMessage.getPushConditionCode())) {
            return AjaxResult.error("推送条件编码不能为空");
        }
        if (StrUtil.equals(MessageConstants.ORDINARY_MESSAGE_TYPE_OUT, ordinaryMessage.getOrdinaryMessageType())) {
            //应用外
            String[] split = ordinaryMessage.getPushChannel().split(",");
            boolean result = Arrays.stream(split).anyMatch(a -> StrUtil.equals(a, MessageConstants.PUSH_CHANNEL_MERCHANT_APPLET) ||
                    StrUtil.equals(a, MessageConstants.PUSH_CHANNEL_RENTER_APPLET));
            if (result) {
                return AjaxResult.error("应用内消息类型的推送渠道不能选择商家小程序或租客小程序");
            }
            //校验消息渠道是否存在
            MessageChannel messageChannel = messageChannelService.selectMessageChannelByTenantId(ordinaryMessage.getTenantId());
            if (ObjectUtil.isEmpty(messageChannel)) {
                return AjaxResult.error("消息渠道不存在,请先配置消息渠道");
            }
            //校验消息渠道是否开启
            for (String pushChannel : split) {
                if (StrUtil.equals(pushChannel, MessageConstants.PUSH_CHANNEL_ENTERPRISE_WECHAT) &&
                        StrUtil.equals(Constants.SHUT, messageChannel.getWechatState())) {
                    return AjaxResult.error("企业微信未开启,请先开启企业微信渠道");
                }
                if (StrUtil.equals(pushChannel, MessageConstants.PUSH_CHANNEL_DING_TALK) &&
                        StrUtil.equals(Constants.SHUT, messageChannel.getDingState())) {
                    return AjaxResult.error("钉钉未开启,请先开启钉钉渠道");
                }
            }
        } else if (StrUtil.equals(MessageConstants.ORDINARY_MESSAGE_TYPE_IN, ordinaryMessage.getOrdinaryMessageType())) {
            //应用内
            if (ordinaryMessage.getPushChannel().split(",").length > 1) {
                throw new ServiceException("应用内推送渠道只能单选");
            }
            if (StrUtil.equals(ordinaryMessage.getPushChannel(), MessageConstants.PUSH_CHANNEL_ENTERPRISE_WECHAT) ||
                    StrUtil.equals(ordinaryMessage.getPushChannel(), MessageConstants.PUSH_CHANNEL_DING_TALK)) {
                return AjaxResult.error("应用内消息类型的推送渠道不能选择企业微信或钉钉");
            }
        }
        return null;
    }
}
